﻿using ProtoBuf.Meta;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SyncDemo.Sync.Utils
{
    public class MemoryBufferTypeSerializeException : Exception
    {

    }

    public class ExMemoryBuffer : MemoryBuffer
    {
        private RuntimeTypeModel _typeModel;
        private Dictionary<Type, int> _typeFieldNumberMap = new Dictionary<Type, int>();
        protected override void Loaded()
        {
            _typeModel = RuntimeTypeModel.Create();

            base.Loaded();
        }

        public void InitTypes(IEnumerable<Type> types)
        {
            var counter = 0;
            foreach (var type in types)
            {
                counter++;
                _typeFieldNumberMap.Add(type, counter);
                _typeModel.Add(type);
            }
        }

        private int GetTypeFieldNumber(Type type)
        {
            return _typeFieldNumberMap[type];
        }

        private int GetTypeFieldNumber<T>()
        {
            return GetTypeFieldNumber(typeof(T));
        }

        private bool HasType(Type type)
        {
            return _typeFieldNumberMap.ContainsKey(type);
        }
        private bool HasType<T>()
        {
            return HasType(typeof(T));
        }

        public override void Serialize<T>(T obj)
        {
            if (HasType<T>() == false) new MemoryBufferTypeSerializeException();
            var fieldNumber = GetTypeFieldNumber<T>();
            _sendMemoryStream.Seek(0, SeekOrigin.Begin);
            _typeModel.SerializeWithLengthPrefix(_sendMemoryStream, obj, typeof(T), ProtoBuf.PrefixStyle.Base128, fieldNumber);
        }

        public override bool TryDeserialize<T>(out T result)
        {
            result = default;
            if (HasType<T>() == false) return false;
            var fieldNumber = GetTypeFieldNumber<T>();
            //_memoryStream.Seek(0, SeekOrigin.Begin);
            //_memoryStream.Write(Buffer, 0, Buffer.Length); // 将Buffer的内容写入

            _receiveMemoryStream.Seek(0, SeekOrigin.Begin);

            try
            {
                result = (T)_typeModel.DeserializeWithLengthPrefix(_receiveMemoryStream, null, typeof(T), ProtoBuf.PrefixStyle.Base128, fieldNumber);
            }
            catch (Exception)
            {
                //throw new MemoryBufferTypeSerializeException();
                return false;
            }

            return true;
        }
    }
}
